In [1]:
inferior = 0.0
superior = 1.0
λ = 0.05 # Unicode characters are allowed as names: \lambda<tab>
inferior <= λ <= superior
Out[1]:
Julia posee varios built-in types
, como Float64
que representa a un número de coma flotante de 64 bits. Pero lo interesante es que los types
creados por los usuarios son tan rápidos como los built-in.
In [2]:
typeof(λ)
Out[2]:
In [3]:
λ::Float64 # Type assertion
Out[3]:
In [4]:
λ::Int # Type assertion
De hecho, Julia es un lenguaje homoiconico, por lo que su biblioteca base está escrita en Julia.
La definición de Float64
en Julia es:
abstract Number
abstract Real <: Number
abstract FloatingPoint <: Real
bitstype 32 Float32 <: FloatingPoint
bitstype 64 Float64 <: FloatingPoint
In [5]:
super(Float64)
Out[5]:
In [6]:
subtypes(FloatingPoint)
Out[6]:
Julia es JIT (just-in-time) compiled, por lo que la primera vez que se llama a una función, su tiempo de ejecución es más lento (porque es compilada) pero la segunda vez es casi tan rápida como si corriera en C (dado que fue compilada específicamente para el tipo de datos de sus argumentos)
In [7]:
@elapsed λ * 100
Out[7]:
In [8]:
@elapsed λ * 100
Out[8]:
Para Julia es posible elegir el método más específico para cada combinación de tipos de argumentos, debido a su diseño basado en multiple dispatch. Uno puede preguntar por el método que se ejecutó usando el macro @which
In [9]:
@which λ * 100::Int
Out[9]:
In [10]:
@which λ * Float64(100)
Out[10]:
In [11]:
lista = [1, λ, π, "Hola mundo"]
Out[11]:
In [12]:
typeof(lista)
Out[12]:
Si un array contiene siempre un mismo tipo de datos, su almacenamiento en memoria es más eficiente si lo declaramos. A su vez las funciones que lo utilizan se ejecutarán de manera más eficiente/rápida (porque el compilador puede predecir el tipo de datos que va a obtener de array).
In [13]:
identidad = Float64[62, 95, 99, 30]
Out[13]:
In [14]:
identidad[1] # Los Arrays se acceden desde 1
Out[14]:
In [15]:
identidad[2:3] # Es posible acceder usando rangos start:end
Out[15]:
In [16]:
identidad[end] = 100 # Es posible asignar un elemento a un índice en particular, "end" permite obtener el último ítem
identidad
Out[16]:
Es posible indexar un array usando otro array, por ejemplo usando arrays lógicos
In [17]:
usar = identidad .> 95.0 # .> compara el array elemento a elemento
Out[17]:
In [18]:
identidad[ usar ]
Out[18]:
Existen varias dequeue functions en Julia. Dado que modifican el array que reciben, por cenvención sus nombres terminan en !
, por ejemplo:
push! # Al final del array
pop!
shift! # Al inicio del array
unshift!
splice! # En medio del array
In [19]:
push!(identidad, 30)
identidad
Out[19]:
In [20]:
segundo = splice!(identidad, 2)
Out[20]:
In [21]:
identidad
Out[21]:
In [22]:
matrix = [ 0.5 0.6
0.7 0.8 ]
Out[22]:
In [23]:
matrix[2,1] # Fila 2, Columna 1
Out[23]:
In [24]:
matrix[3] # La matriz se almacena de manera continua en memoria; column-major order.
Out[24]:
In [25]:
map = Dict('A'=>1, 'B'=>2, 'C'=>3)
Out[25]:
In [26]:
map['D'] = 4 # Agrega un nuevo par (Pair) llave => valor al diccionario
Out[26]:
In [27]:
map['A'] = 5 # Si la llave ya existe, el valor es reemplazado
map
Out[27]:
In [28]:
map['B']
Out[28]:
In [29]:
map['E'] # Error: 'E' no está en map
In [30]:
get(map, 'E', 0) # Es posible usar get para definir un valor default que evite el error
Out[30]:
In [31]:
haskey(map, 'E') # O (1)
Out[31]:
In [32]:
'E' in keys(map) # Notación similar a la de Python
Out[32]:
In [33]:
'E' ∈ keys(map) # \in<tab> para una notación más matemática de la pertenencia
Out[33]:
In [34]:
array = ['A', 'B', 'C', 'D', 'D', 'D']
'E' in array # O(n)
Out[34]:
In [35]:
conjunto = Set(array) # Conjunto de valores únicos
Out[35]:
In [36]:
'E' in conjunto # O(1)
Out[36]:
In [37]:
identidad = rand() * 100.0
Out[37]:
In [38]:
if identidad == 100.0
println("Idénticas")
elseif identidad >= 30 # Opcional
println("Homólogas")
else # Opcional
println("Twilight")
end
In [39]:
numero = rand(1:100)
Out[39]:
In [40]:
if numero % 2 == 0
es_par = "si"
else
es_par = "no"
end
es_par
Out[40]:
In [41]:
es_par = numero % 2 == 0 ? "si" : "no"
Out[41]:
In [42]:
numero % 2 == 0 && println("par")
Out[42]:
In [43]:
numero % 2 != 0 && println("impar")
In [44]:
numero = 0
limite = 3
while numero < limite
numero += 1
println(numero)
end
In [45]:
carpeta = "data"
archivos = readdir(carpeta)
Out[45]:
In [46]:
for nombre in archivos # for arch = archivos
println(nombre)
end
En Julia los for
s son reescritos como while
s, usando las funciones start
para inicializar la iteración, done
para testear si se alcanzó el final de la iteración y next
para obtener el valor de la iteración y el del próximo estado. Uno puede definir estas funciones para cualquier tipo propio que quiera hacer iterable.
In [47]:
state = start(archivos) # state = 1
while !done(archivos, state) # !( state > length(archivos) )
(nombre, state) = next(archivos, state) # archivos[state], state + 1
println(nombre)
end
In [48]:
for nombre in archivos
println( joinpath(carpeta, nombre) )
end
In [49]:
len = length(archivos)
lista = Array(Int, len)
for i in 1:len
lista[i] = filesize(joinpath(carpeta, archivos[i])) # Tamaño en bytes
end
lista
Out[49]:
In [50]:
lista = [ filesize(joinpath(carpeta, nombre)) for nombre in archivos ]
Out[50]:
Los strings son secuencias finitas de caracteres. En sus principios la bioinformática se trató del análisis de secuencias de caracteres (utilizando la codificación ASCII de 8 bits), lo que hizo popular a Perl en el área. Julia tiene un buen soporte para strings:
In [51]:
cadena_unicode = "∃x ∈ B ∧ x ∈ A"
Out[51]:
In [52]:
typeof(cadena_unicode)
Out[52]:
In [53]:
cadena_ascii = "A es un subconjunto de B"
Out[53]:
In [54]:
typeof(cadena_ascii)
Out[54]:
Es seguro iterar sobre un string (inmutable) para obtener sus caracteres. Si se quiere obtener un Vector{Char}
(Array
de una dimensión, mutable) se puede usar list comprehension o la función collect
.
In [55]:
for char in cadena_ascii
print(char)
end
In [56]:
for char in cadena_unicode
print(char)
end
In [57]:
collect(cadena_unicode) # [ char for char in cadena_unicode ]
Out[57]:
Sin embargo, acceder directamente a un string como si fuera un array no es una acción segura dado que un carácter puede estar codificado por más de un valor de 8 bits. Sólo es seguro hacer eso para ASCIIString
s, dado que cada carácter está codificado por un sólo número entero de 8 bits. Pero no es seguro hacerlo para otras codificación. Por ejemplo, la codificación UTF-8 de ∃ (\exists<tab>
en la consola) requiere de tres valores de 8 bits:
In [58]:
for i in 1:4
println(i, " ", cadena_ascii[i])
end
In [59]:
for i in 1:4
try
println(i, " ", cadena_unicode[i])
catch err
println(i, " ", err) # Error al acceder cadena_unicode[i]
end
end
In [60]:
ext_fasta = r"\.fasta$" # r"... permite escribir una expresión regular
Out[60]:
In [61]:
typeof(ext_fasta)
Out[61]:
In [62]:
for nombre in archivos
println(nombre, "\t:\t", ismatch(ext_fasta, nombre)) # ismatch es true si la regex está en el string
end
In [63]:
ismatch(r"^>\w{4}\.\w", ">2trx.A")
Out[63]:
In [64]:
ismatch(r"^∃x\s+", cadena_unicode) # UNICODE UTF-8
Out[64]:
In [65]:
captura = match(r"^>(\w{4})\.(\w)", ">2trx.A")
Out[65]:
In [66]:
if captura != nothing
println("PDB\t", captura[1]) # captura[1] == captura.captures[1]
println("Cadena\t", captura[2])
else
println("No es un PDB ID")
end
In [67]:
captura = match(r"^>(\w{4})\.(\w)", ">PF00085") # nothing no imprime nada en pantalla
In [68]:
if captura != nothing
println("PDB\t", captura[1])
println("Cadena\t", captura[2])
else
println("No es un PDB ID")
end
In [69]:
captura = match(r"^>(?'pdb'\w{4})\.(?<cad>\w)", ">2trx.A")
Out[69]:
In [70]:
captura[:pdb] # :... es un Symbol en Julia (los nombres de variables, funciones, etc son símbolos)
Out[70]:
In [71]:
A, B = rand(1:6), rand(1:6)
"Su dado es $A, mientras el dado de Julia es $B: $( A > B ? "usted gana" : A != B ? "Julia gana" : "empate")"
Out[71]:
In [72]:
fasta_2trx = """
>2TRX:A|PDBID|CHAIN|SEQUENCE
SDKIIHLTDDSFDTDVLKADGAILVDFWAEWCGPCKMIAPILDEIADEYQGKLTVAKLNIDQNPGTAPKYGIRGIPTLLL
FKNGEVAATKVGALSKGQLKEFLDANLA
>2TRX:B|PDBID|CHAIN|SEQUENCE
SDKIIHLTDDSFDTDVLKADGAILVDFWAEWCGPCKMIAPILDEIADEYQGKLTVAKLNIDQNPGTAPKYGIRGIPTLLL
FKNGEVAATKVGALSKGQLKEFLDANLA
"""
Out[72]:
In [73]:
print(fasta_2trx)
In [74]:
"""Una línea, pero con "comillas" simples"""
Out[74]:
In [75]:
stream = open("data/PF09645_full.fasta", "r")
Out[75]:
In [76]:
for line in eachline(stream) # Itero para cada línea (incluye '\n')
print(line)
end
In [77]:
close(stream)
open( … ) do … asegura que el archivo se cierre si ocurre algún error (implemente un try/catch)
In [78]:
open("data/PF09645_full.fasta", "r") do stream
for line in eachline(stream)
print(line)
end
end
In [79]:
function listaralineamientos(direccion, extension::Regex=r"\.fasta$"; vacios::Bool=false)
archivos = readdir(direccion)
alns = ASCIIString[]
for nombre in archivos
if ismatch(extension, nombre)
if vacios || filesize(joinpath(direccion, nombre)) >0
push!(alns, nombre)
end
end
end
alns
end
Out[79]:
In [80]:
listaralineamientos("data")
Out[80]:
In [81]:
listaralineamientos("data", vacios=true)
Out[81]:
In [82]:
methods(listaralineamientos)
Out[82]:
In [83]:
listaralineamientos("data", r"\.stockholm$")
Out[83]:
In [84]:
listarstockholm(carpeta) = listaralineamientos(carpeta, r"\.stockholm$")
Out[84]:
In [85]:
methods(listarstockholm)
Out[85]:
In [86]:
@doc """
```listaralineamientos(direccion, extension::Regex=r"\.fasta\$"; vacios::Bool=false)```
Retorna una lista de los archivos de alineamientos en la `dirección`. Por defecto busca archivos con extensión fasta que no estén vacíos.
""" listaralineamientos
In [87]:
?listaralineamientos
Out[87]:
In [88]:
"Muestra las primeras `n` líneas de los archivos fastas en la `carpeta`"
function head_fastas(carpeta, n::Int=10)
for nombre in listaralineamientos(carpeta)
println("# ---- $nombre ---- #")
run(`head -$n $( joinpath(carpeta, nombre) )`) # Corre un comando/programa externo
end
end
Out[88]:
In [89]:
?head_fastas
Out[89]:
In [90]:
head_fastas("data", 4)
In [91]:
head_fastas("data", n=4) # n es posicional, no es un keyword argument
In [92]:
# Pkg.add("Gadfly")
# Pkg.add("RDatasets")
In [93]:
using Gadfly # Similar a ggplot2 de R
using RDatasets # Los datasets de ejemplos de R
iris = dataset("datasets", "iris")
describe(iris) # summary(iris) en R
In [94]:
plot(iris, x="Species", y="PetalLength", color="Species", Geom.boxplot)
Out[94]:
In [95]:
plot(iris, color="Species", x="PetalLength", Geom.histogram)
Out[95]:
In [96]:
plot(iris, x=:PetalLength, y=:PetalWidth, color=:Species, Geom.point, Geom.smooth(method=:lm))
Out[96]:
In [97]:
# Pkg.add("GLM")
In [98]:
using GLM
linear = fit(LinearModel, PetalWidth ~ PetalLength, iris) # PetalLength en R: 0.4157554
Out[98]:
In [99]:
# Pkg.add("MIToS")
In [100]:
using MIToS.MSA
In [101]:
aln = read("data/PF09645_full.stockholm", Stockholm, generatemapping=true, useidcoordinates=true)
Out[101]:
In [102]:
print(aln)
In [103]:
print(aln, FASTA)
In [104]:
write("output", read("data/PF09645_full.stockholm", Stockholm), FASTA) # Stockholm to FASTA (simple)
In [105]:
open("output", "r") do fh
for line in eachline(fh)
print(line)
end
end